package pATT.DataSetsGenerator.dataSetsGenerator.generator.implement;

import java.util.Vector;

import pATT.DataSetsGenerator.dataSetsGenerator.core.implement.Relation;
import pATT.DataSetsGenerator.dataSetsGenerator.data.implement.IData;
import pATT.DataSetsGenerator.dataSetsGenerator.data.implement.RandomGaussianData;

public class RandomGaussianGenerator extends Generator{
	
//	Constants for the normal() method:
	private static final double p0 = 0.322232431088;     
	private static final double q0 = 0.099348462606;
	private static final double p1 = 1.0;                
	private static final double q1 = 0.588581570495;
	private static final double p2 = 0.342242088547;     
	private static final double q2 = 0.531103462366;
	private static final double p3 = 0.204231210245e-1;  
	private static final double q3 = 0.103537752850;
	private static final double p4 = 0.453642210148e-4;  
	private static final double q4 = 0.385607006340e-2;
	
	
	
	public RandomGaussianGenerator(Relation relat) {
		super(relat);
	}
	
	@SuppressWarnings("unchecked")
	public Vector generate(IData data){
		if(((RandomGaussianData)data).getMu() != -1){
			Vector instances = ((RandomGaussianData)data).getAttribute().getValues(); 
			int cantRules = getRelation().getExamples();
			Vector result= new Vector();
			int i = 0; 
			double doub,mu,sigma;
			RandomGaussianData gr=(RandomGaussianData)data;
			mu=gr.getMu();
			sigma=gr.getSigma();
			while(i < cantRules) {
				doub = normal(mu,sigma);// (0<media<cantidad de instancias-1), doub me da el valor dentro de las instancias 
				if((doub < instances.size())&&(doub > 0)){
					result.addElement(instances.elementAt(((int)doub)));
					i++;
				}
			}
			return result;
		}
		else{
			System.out.println("------------->FUe al random comun");
			return (new RandomGenerator(relation)).generate(data);
		}
	}
	
	public double normal(double mu,double sigma){
		/* ========================================================================
		 * Returns a normal (Gaussian) distributed real number.
		 * NOTE: use sigma > 0.0
		 * ========================================================================
		 */ 
		double u, t, p, q, z;
		
		u   = Math.random();
		if (u < 0.5)
			t = Math.sqrt(-2.0 * Math.log(u));
		else
			t = Math.sqrt(-2.0 * Math.log(1.0 - u));
		p   = p0 + t * (p1 + t * (p2 + t * (p3 + t * p4)));
		q   = q0 + t * (q1 + t * (q2 + t * (q3 + t * q4)));
		if (u < 0.5)
			z = (p / q) - t;
		else
			z = t - (p / q);
		return (mu + sigma * z);
	}
}
